问:
Refreshing terminal session with Python and os.system()
I'm trying to write a cli tool that manages aliases and I want the script to be able to refresh the terminal session by running source ~/.zshrc or equivalent.

When I run os.system('source ~/.zshrc') in my script, I get this error

```<code>/Users/hydenpolikoff/.zshrc: line 4: ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh: bad substitution
/Users/hydenpolikoff/.zshrc: line 34: zstyle: command not found
/Users/hydenpolikoff/.zshrc: line 37: zstyle: command not found
Error: Oh My Zsh can't be loaded from: sh. You need to run zsh instead.
Here's the process tree:

 PPID   PID COMMAND
    1 64923 /Applications/iTerm.app/Contents/MacOS/iTerm2
64923 64924 /Users/hydenpolikoff/Library/Application Support/iTerm2/iTermServer-3.4.13 /Users/hydenpolikoff/Library/Application Support/iTerm2/iterm2-daemon-1.socket
64924 66181 login -fp hydenpolikoff
66181 66182 -zsh
66182 66448 /Users/hydenpolikoff/.pyenv/versions/3.9.5/bin/python3
66448 66468 sh -c source ~/.zshrc

/Users/hydenpolikoff/.p10k.zsh: line 16: local: can only be used in a function
/Users/hydenpolikoff/.p10k.zsh: line 20: builtin: setopt: not a shell builtin
/Users/hydenpolikoff/.p10k.zsh: line 22: syntax error near unexpected token `)'
/Users/hydenpolikoff/.p10k.zsh: line 22: `() {'
/opt/homebrew/opt/fzf/shell/key-bindings.zsh: line 22: syntax error near unexpected token `)'
/opt/homebrew/opt/fzf/shell/key-bindings.zsh: line 22: `  () {'
256
</code>```

When I use os.system('zsh ~/.zshrc') as it suggests, the command executes without an error, however, the terminal session is not refreshed  as the alias I added is not available in the current session.

Does anybody have any ideas how I might solve this?

Here is the code for the entry points if this makes more sense

```<code>import click
import os

from nav.alias_db import AliasDB
from nav.pretty_printer import Printer
from nav.file_handler import FileHandler

def refresh_session():
    """
    function to reload the session if auto_reload has been set to true
    """

    global_vars = FileHandler.read_globals()
    if 'auto_reload' not in global_vars:
        global_vars['auto_reload'] = 'false'

    if global_vars['auto_reload'] == 'true':
        if global_vars['shell'] == 'zsh':
            click.echo('Refreshing session...')
            os.system('zsh $HOME/.zshrc')
        elif global_vars['shell'] == 'bash':
            click.echo('Refreshing session...')
            os.system('bash ~/.bashrc')
        else:
            click.echo('navi is not configured to refresh your session, please do so manually!')

# create the nav group of commands
@click.group()
def nav() -> None:
    """
    Manage navigation aliases
    """
    pass

@nav.command()
@click.argument('alias', type=str)
def add(alias):
    """
    Add alias to navigate to current directory with alias as argument
    """

    # add the alias to the db and then write to the file
    if AliasDB.insert(alias, os.getcwd(), None):
        FileHandler.write_cd(alias, os.getcwd())
        click.echo(f'Alias {alias} added successfully')
        refresh_session()

@nav.command()
@click.argument('alias', type=str)
def update(alias):
    """
    If an alias exists for the current working directory, update it with the argument provided
    """

    res = AliasDB.search_cwd(os.getcwd())
    if res is not None:
        AliasDB.update(res[0], os.getcwd(), alias)
        cmds = AliasDB.fetch_all()
        FileHandler.refresh(cmds)
        click.echo(f'Alias updated, new alias to cwd is {alias}')
        refresh_session()
    else:
        click.echo('No alias to update for the current directory')

@nav.command()
@click.argument('alias', type=str, required=False)
def remove(alias):
    """
    Remove alias to current directory if no argument provided, and it exists. If alias arg is provided, remove the
    provided alias
    """

    if alias is None:
        query_res = AliasDB.search_cwd(os.getcwd())
        if query_res is not None:
            AliasDB.delete(query_res[0])
            click.echo(f'Alias {query_res[0]} for the cwd removed successfully')
            refresh_session()
        else:
            click.echo('There is no alias to remove for the cwd')
    else:
        if AliasDB.delete(alias):
            cmds = AliasDB.fetch_all()
            FileHandler.refresh(cmds)
            click.echo(f'Alias {alias} removed successfully')
            refresh_session()

@nav.command()
def list():
    """
    List all aliases
    """

    # fetch all the aliases and print them out
    headers = ['Alias', 'Directory']
    cmds = AliasDB.fetch_all()
    if len(cmds) == 0:
        click.echo('No aliases currently setup with navi')
    else:
        Printer.pretty_print(headers, cmds, True)

@nav.command()
def search():
    """
    Search for if there is an alias for the current working directory
    """

    query_res = AliasDB.search_cwd(os.getcwd())
    if query_res is None:
        click.echo('No alias for found the current working directory')
    else:
        click.echo(f'{query_res[0]} is the alias for the current working directory')

@nav.command()
@click.argument('show', default='')
def config(show):
    """
    Configure if you're using zsh or bash and weather to auto reload the shell
    """

    if show in ['show', 's']:
        # showing the global vars
        gls = FileHandler.read_globals()
        if gls != {}:
            data = []
            headings = ['Global', 'Value']
            for k in gls:
                data.append((k, gls[k]))
            Printer.pretty_print(headings, data)
        else:
            click.echo('No globals currently configured. Run navi config or navi set <global> <value> to set them.')
    else:
        # setting up shell choice
        shell = os.getenv('SHELL')
        shell_choice = True
        if 'zsh' in shell:
            FileHandler.update_global('shell', 'zsh')
            click.echo('We detected you are running zsh. navi shell type has been configured.')
            shell_choice = False
        elif 'bash' in shell:
            FileHandler.update_global('shell', 'bash')
            click.echo('We detected you are running bash. navi shell type has been configured.')
            shell_choice = False
        else:
            click.echo('Uh oh, not sure what type of terminal you are running')

        # if shell can't be figured out automatically
        while shell_choice:
            click.echo('Are you using zsh or bash? Please enter 1 or 2')
            click.echo('1: zsh\n2: bash')
            value = click.prompt('>', type=int)
            if value == 1:
                FileHandler.update_global('shell', 'zsh')
                click.echo('navi has been configured for zsh.')
                shell_choice = False
            elif value == 2:
                FileHandler.update_global('shell', 'bash')
                click.echo('navi has been configured for bash.')
                shell_choice = False
            else:
                click.echo('Please enter a valid option')

        # setting up auto_reload choice
        auto_load_choice = True
        while auto_load_choice:
            click.echo('Would you like to auto-reload your shell after add/update/remove commands?')
            click.echo('1: Yes, auto-reload\n2: No, don\'t auto-reload\n3: What does this mean...')
            choice = click.prompt('>', type=int)
            if choice == 1:
                FileHandler.update_global('auto_reload', 'true')
                click.echo('navi has been configured for auto-reload')
                auto_load_choice = False
            elif choice == 2:
                FileHandler.update_global('auto_reload', 'false')
                click.echo('navi has been configured not to auto-reload')
                auto_load_choice = False
            elif choice == 3:
                click.echo('''
                In order for your alias to work, you need to reload your terminal session.
                Ff you select yes, the command will run automatically after you add/update/remove.
                This will slow down navi but it won't be any faster to run it yourself.
                ''')
            else:
                click.echo('Please enter a valid option')

@nav.command()
@click.argument('global_to_set', nargs=2)
def set(global_to_set):
    """
    Set the shell type and auto_reload configs without using the config command
    """

    if global_to_set[0] in ['auto_reload', 'ar'] :
        if global_to_set[1] in ['true', 'false']:
            FileHandler.update_global('auto_reload', global_to_set[1])
            click.echo(f'auto_reload has been set to {global_to_set[1]}')
        else:
            click.echo('Invalid auto_reload arg, accepted inputs are:\ntrue\nfalse')
    elif global_to_set[0] == 'shell':
        if global_to_set[1] in ['bash', 'zsh']:
            FileHandler.update_global(global_to_set[0], global_to_set[1])
            click.echo(f'shell has been set to {global_to_set[1]}')
        else:
            click.echo('Invalid shell type, accepted inputs are:\nzsh\nbash')
    else:
        click.echo('There is no global for that in navi')

if __name__ == '__main__':
    nav()
</code>```

答: Per the comments, there is no way to do this unfortunately!</p>

Body:
I'm trying to write a cli tool that manages aliases and I want the script to be able to refresh the terminal session by running source ~/.zshrc or equivalent.

When I run os.system('source ~/.zshrc') in my script, I get this error

/Users/hydenpolikoff/.zshrc: line 4: ${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh: bad substitution
/Users/hydenpolikoff/.zshrc: line 34: zstyle: command not found
/Users/hydenpolikoff/.zshrc: line 37: zstyle: command not found
Error: Oh My Zsh can't be loaded from: sh. You need to run zsh instead.
Here's the process tree:

 PPID   PID COMMAND
    1 64923 /Applications/iTerm.app/Contents/MacOS/iTerm2
64923 64924 /Users/hydenpolikoff/Library/Application Support/iTerm2/iTermServer-3.4.13 /Users/hydenpolikoff/Library/Application Support/iTerm2/iterm2-daemon-1.socket
64924 66181 login -fp hydenpolikoff
66181 66182 -zsh
66182 66448 /Users/hydenpolikoff/.pyenv/versions/3.9.5/bin/python3
66448 66468 sh -c source ~/.zshrc

/Users/hydenpolikoff/.p10k.zsh: line 16: local: can only be used in a function
/Users/hydenpolikoff/.p10k.zsh: line 20: builtin: setopt: not a shell builtin
/Users/hydenpolikoff/.p10k.zsh: line 22: syntax error near unexpected token `)'
/Users/hydenpolikoff/.p10k.zsh: line 22: `() {'
/opt/homebrew/opt/fzf/shell/key-bindings.zsh: line 22: syntax error near unexpected token `)'
/opt/homebrew/opt/fzf/shell/key-bindings.zsh: line 22: `  () {'
256

When I use os.system('zsh ~/.zshrc') as it suggests, the command executes without an error, however, the terminal session is not refreshed  as the alias I added is not available in the current session.

Does anybody have any ideas how I might solve this?

Here is the code for the entry points if this makes more sense

import click
import os

from nav.alias_db import AliasDB
from nav.pretty_printer import Printer
from nav.file_handler import FileHandler

def refresh_session():
    """
    function to reload the session if auto_reload has been set to true
    """

    global_vars = FileHandler.read_globals()
    if 'auto_reload' not in global_vars:
        global_vars['auto_reload'] = 'false'

    if global_vars['auto_reload'] == 'true':
        if global_vars['shell'] == 'zsh':
            click.echo('Refreshing session...')
            os.system('zsh $HOME/.zshrc')
        elif global_vars['shell'] == 'bash':
            click.echo('Refreshing session...')
            os.system('bash ~/.bashrc')
        else:
            click.echo('navi is not configured to refresh your session, please do so manually!')

# create the nav group of commands
@click.group()
def nav() -> None:
    """
    Manage navigation aliases
    """
    pass

@nav.command()
@click.argument('alias', type=str)
def add(alias):
    """
    Add alias to navigate to current directory with alias as argument
    """

    # add the alias to the db and then write to the file
    if AliasDB.insert(alias, os.getcwd(), None):
        FileHandler.write_cd(alias, os.getcwd())
        click.echo(f'Alias {alias} added successfully')
        refresh_session()

@nav.command()
@click.argument('alias', type=str)
def update(alias):
    """
    If an alias exists for the current working directory, update it with the argument provided
    """

    res = AliasDB.search_cwd(os.getcwd())
    if res is not None:
        AliasDB.update(res[0], os.getcwd(), alias)
        cmds = AliasDB.fetch_all()
        FileHandler.refresh(cmds)
        click.echo(f'Alias updated, new alias to cwd is {alias}')
        refresh_session()
    else:
        click.echo('No alias to update for the current directory')

@nav.command()
@click.argument('alias', type=str, required=False)
def remove(alias):
    """
    Remove alias to current directory if no argument provided, and it exists. If alias arg is provided, remove the
    provided alias
    """

    if alias is None:
        query_res = AliasDB.search_cwd(os.getcwd())
        if query_res is not None:
            AliasDB.delete(query_res[0])
            click.echo(f'Alias {query_res[0]} for the cwd removed successfully')
            refresh_session()
        else:
            click.echo('There is no alias to remove for the cwd')
    else:
        if AliasDB.delete(alias):
            cmds = AliasDB.fetch_all()
            FileHandler.refresh(cmds)
            click.echo(f'Alias {alias} removed successfully')
            refresh_session()

@nav.command()
def list():
    """
    List all aliases
    """

    # fetch all the aliases and print them out
    headers = ['Alias', 'Directory']
    cmds = AliasDB.fetch_all()
    if len(cmds) == 0:
        click.echo('No aliases currently setup with navi')
    else:
        Printer.pretty_print(headers, cmds, True)

@nav.command()
def search():
    """
    Search for if there is an alias for the current working directory
    """

    query_res = AliasDB.search_cwd(os.getcwd())
    if query_res is None:
        click.echo('No alias for found the current working directory')
    else:
        click.echo(f'{query_res[0]} is the alias for the current working directory')

@nav.command()
@click.argument('show', default='')
def config(show):
    """
    Configure if you're using zsh or bash and weather to auto reload the shell
    """

    if show in ['show', 's']:
        # showing the global vars
        gls = FileHandler.read_globals()
        if gls != {}:
            data = []
            headings = ['Global', 'Value']
            for k in gls:
                data.append((k, gls[k]))
            Printer.pretty_print(headings, data)
        else:
            click.echo('No globals currently configured. Run navi config or navi set <global> <value> to set them.')
    else:
        # setting up shell choice
        shell = os.getenv('SHELL')
        shell_choice = True
        if 'zsh' in shell:
            FileHandler.update_global('shell', 'zsh')
            click.echo('We detected you are running zsh. navi shell type has been configured.')
            shell_choice = False
        elif 'bash' in shell:
            FileHandler.update_global('shell', 'bash')
            click.echo('We detected you are running bash. navi shell type has been configured.')
            shell_choice = False
        else:
            click.echo('Uh oh, not sure what type of terminal you are running')

        # if shell can't be figured out automatically
        while shell_choice:
            click.echo('Are you using zsh or bash? Please enter 1 or 2')
            click.echo('1: zsh\n2: bash')
            value = click.prompt('>', type=int)
            if value == 1:
                FileHandler.update_global('shell', 'zsh')
                click.echo('navi has been configured for zsh.')
                shell_choice = False
            elif value == 2:
                FileHandler.update_global('shell', 'bash')
                click.echo('navi has been configured for bash.')
                shell_choice = False
            else:
                click.echo('Please enter a valid option')

        # setting up auto_reload choice
        auto_load_choice = True
        while auto_load_choice:
            click.echo('Would you like to auto-reload your shell after add/update/remove commands?')
            click.echo('1: Yes, auto-reload\n2: No, don\'t auto-reload\n3: What does this mean...')
            choice = click.prompt('>', type=int)
            if choice == 1:
                FileHandler.update_global('auto_reload', 'true')
                click.echo('navi has been configured for auto-reload')
                auto_load_choice = False
            elif choice == 2:
                FileHandler.update_global('auto_reload', 'false')
                click.echo('navi has been configured not to auto-reload')
                auto_load_choice = False
            elif choice == 3:
                click.echo('''
                In order for your alias to work, you need to reload your terminal session.
                Ff you select yes, the command will run automatically after you add/update/remove.
                This will slow down navi but it won't be any faster to run it yourself.
                ''')
            else:
                click.echo('Please enter a valid option')

@nav.command()
@click.argument('global_to_set', nargs=2)
def set(global_to_set):
    """
    Set the shell type and auto_reload configs without using the config command
    """

    if global_to_set[0] in ['auto_reload', 'ar'] :
        if global_to_set[1] in ['true', 'false']:
            FileHandler.update_global('auto_reload', global_to_set[1])
            click.echo(f'auto_reload has been set to {global_to_set[1]}')
        else:
            click.echo('Invalid auto_reload arg, accepted inputs are:\ntrue\nfalse')
    elif global_to_set[0] == 'shell':
        if global_to_set[1] in ['bash', 'zsh']:
            FileHandler.update_global(global_to_set[0], global_to_set[1])
            click.echo(f'shell has been set to {global_to_set[1]}')
        else:
            click.echo('Invalid shell type, accepted inputs are:\nzsh\nbash')
    else:
        click.echo('There is no global for that in navi')

if __name__ == '__main__':
    nav()


来源: stackexchange

问:
Chart.js how to use scriptable options
I am migrating chart.js to 3.x as per the migration guide.

https://www.chartjs.org/docs/master/getting-started/v3-migration/

I am trying to set the xAxis zeroLineColor to "#FFFFFF" and I want to have the Grid line color as "#00FFFF" but as per the chart.js migration document document scales.[x/y]Axes.zeroLine* options of axes were removed. Use scriptable scale options instead.

I am not sure how to use scriptable scale options for setting the xAxis line zero to white.

Update:

Working example:

https://jsfiddle.net/g4vq7o2b/2/

答:
Using chart_v3.7.0.js cartesian time axis, for me, configuring zeroline and other gridlines works, using scriptable options.
Apply property for "context.tick.value == 0"  (=baseline)
like:
...</p>
```<code>options: {
            scales: {

                x: {
                        gridLines: {
                          color: "#00ff00",
                        },
                        ticks: {        font: { size: 30    },
                                        maxRotation: 90,
                                        minRotation: 90,
                                },
                        type: 'time',
                        time: {
                                /*tooltipFormat: "DD.MM hh:mm",*/
                                displayFormats: {
                                    minute: 'HH:mm',
                                    hour: 'HH:mm',
                                    day: 'dd.MMM',
                                }
                        },
                },

                y: {
                        grid: {
                            color: (line) => (line.index === 0 ? 'red' : 'rgba(0, 0, 0, 0.1)') //color of lowest horizontal grid line
                            color: context => context.tick.value == 0 ? "#FFFFFF" : "#00FFFF", // zero-line baseline color
                            lineWidth: context => context.tick.value == 0 ? 3 : 1, // zero-line baseline width
                        },
                        position: 'right', // show axis on the right
                        title: {        display: true,
                                        rotation: 0,
                                        text: "°C",                 },
                    },

            },
</code>```

ContentLicense: CC BY-SA 4.0

Title: Chart.js how to use scriptable options

Body:
Using chart_v3.7.0.js cartesian time axis, for me, configuring zeroline and other gridlines works, using scriptable options.
Apply property for "context.tick.value == 0"  (=baseline)
like:
...

options: {
            scales: {

                x: {
                        gridLines: {
                          color: "#00ff00",
                        },
                        ticks: {        font: { size: 30    },
                                        maxRotation: 90,
                                        minRotation: 90,
                                },
                        type: 'time',
                        time: {
                                /*tooltipFormat: "DD.MM hh:mm",*/
                                displayFormats: {
                                    minute: 'HH:mm',
                                    hour: 'HH:mm',
                                    day: 'dd.MMM',
                                }
                        },
                },

                y: {
                        grid: {
                            color: (line) => (line.index === 0 ? 'red' : 'rgba(0, 0, 0, 0.1)') //color of lowest horizontal grid line
                            color: context => context.tick.value == 0 ? "#FFFFFF" : "#00FFFF", // zero-line baseline color
                            lineWidth: context => context.tick.value == 0 ? 3 : 1, // zero-line baseline width
                        },
                        position: 'right', // show axis on the right
                        title: {        display: true,
                                        rotation: 0,
                                        text: "°C",                 },
                    },

            },


问:
How do I port code for Borland C++ builder to Linux?
I have source code for a Windows DLL that is written in C++ and uses Visual Component Library. Now my task is to port that to Linux, but I don't have source code for the VCL itself, or any kind of documentation (and I have never worked with Borland C++; in my Windows days I used MFC).

This should not be all that hard, since my DLL does not have any GUI: as far as I can see, it mostly uses VCL for multithreading. I ran into a class that inherits from TThread and that is where I got stuck. I did some search on the Internet, but found no documentation for VCL so far. I would like to avoid buying a book on Borland C++ Builder, because I don't have time to wait for it to arrive from the Amazon. I cannot consider buying the package for Windows, because at work I only have a Linux box.

Any suggestions?

答:
You should be aware that the VCL used by C++ Builder is written entirely in Delphi/ObjectPascal.  c++ builder apps all involve c++ making use of delphi-based libraries.

The FreePascal/Lazarus open source project has reverse-engineered most of the VCL (almost all of the non-visual stuff and much of the visual stuff) and it runs natively on Linux.  The non-visual VCL-compatible stuff is known as the "Free Component Library" ("FCL")
http://www.freepascal.org/
http://www.freepascal.org/fcl/fcl.var

The source of the TThread implementation in the FCL should be easy enough to find.

One option would be to rewrite in FreePascal, where language would change to ObjectPascal but calls to the VCL and usage of VCL components would be virtually identical.

Another option might be to port to c++ on Linux and somehow make use of FreePascal's VCL from c++.  I'm not sure of the practicality/feasibility of that.  Someone at FreePascal's forums should be able to help answer that.

So another option as someone has mentioned would just be to rewrite using some other threading library.

OwnerDisplayName: ajanicij

ContentLicense: CC BY-SA 2.5

OwnerDisplayName: Herbert Sitz


问:
Group column from CSV file and concatenate values of another column, and export back to CSV
This is a follow up to this:
In PowerShell, how can I get the XML inner child to populate its parents and format it in a table?

And it's related to this question:

Group column from CSV file and concatenate values of another column

and this question:

https://superuser.com/questions/453041/grouping-labels-and-concatenating-their-text-values-like-a-pivot-table

My purpose is to grab my csv file and group by the "company" name, and I don't know where to start, I know that PS has a "Group-Object" CmdLet but it returns me an object that I don't know how to deal with.

So, using the example columns that I had before, Harvey from Specter would get from:

PName
Company
ORDERDATE
STREET1
City
ProjectName
Name
Color
OtherData

Charles
Contoso
2022-01-25
FakeStreet 123
San Francisco
Sacramento Expansion
ProductA
Lemon
OtherData

Harvey
Specter
2022-01-25
NotAFake 123
San Diego
North Dakota Expansion
ProductA
Red
OtherData

Harvey
Specter
2022-01-25
NotAFake 123
San Diego
North Dakota Expansion
ProductB
Blue
OtherData

To:

PName
Company
ORDERDATE
STREET1
City
ProjectName
Name
Color
OtherData

Charles
Contoso
2022-01-25
FakeStreet 123
San Francisco
Sacramento Expansion
ProductA
Lemon
OtherData

Harvey
Specter
2022-01-25
NotAFake 123
San Diego
North Dakota Expansion
ProductA, ProductB
Red, Blue
OtherData

Thanks and as always, appreciated

答:
Following your last question and assuming you already have $result stored, this is how you can update the object you already have with the help of Group-Object:

```<code>$result | Group-Object Company | ForEach-Object {
    # If the group is 1 object return it and skip next logic
    if($_.Count -eq 1) { return $_.Group }
    # Capture all objects of this group
    $thisGroup = $_.Group

    # We know if we are here that `$thisGroup` is an object[],
    # there is at least more than 1 object.
    # `$thisObject[0]` is the object we want to update, so,
    # `$thisObject[0].PropertyName` will enumerate ALL Values
    # of "PropertyName" and we can join them with `-join` and assign
    # the result to the 1st Object
    $thisGroup[0].Name  = $thisGroup.Name -join ', ' # Join these elements
    $thisGroup[0].Color = $thisGroup.Color -join ', '
    # Return ONLY the first object of this object[], this is the
    # object that was updated.
    $thisGroup[0]
} | Format-Table -AutoSize
</code>```

Using the same XML and my previous answer to construct $result, the output from above code would be:

```<code>PName   Company ORDERDATE  STREET1        City          ProjectName            Name               Color     OtherData
-----   ------- ---------  -------        ----          -----------            ----               -----     ---------
Charles Contoso 2022-01-25 FakeStreet 123 San Francisco Sacramento Expansion   ProductA           Lemon     OtherData
Harvey  Specter 2022-01-25 NotAFake 123   San Diego     North Dakota Expansion ProductA, ProductB Red, Blue OtherData
</code>```

Body:
Following your last question and assuming you already have $result stored, this is how you can update the object you already have with the help of Group-Object:

$result | Group-Object Company | ForEach-Object {
    # If the group is 1 object return it and skip next logic
    if($_.Count -eq 1) { return $_.Group }
    # Capture all objects of this group
    $thisGroup = $_.Group

    # We know if we are here that `$thisGroup` is an object[],
    # there is at least more than 1 object.
    # `$thisObject[0]` is the object we want to update, so,
    # `$thisObject[0].PropertyName` will enumerate ALL Values
    # of "PropertyName" and we can join them with `-join` and assign
    # the result to the 1st Object
    $thisGroup[0].Name  = $thisGroup.Name -join ', ' # Join these elements
    $thisGroup[0].Color = $thisGroup.Color -join ', '
    # Return ONLY the first object of this object[], this is the
    # object that was updated.
    $thisGroup[0]
} | Format-Table -AutoSize

Using the same XML and my previous answer to construct $result, the output from above code would be:

PName   Company ORDERDATE  STREET1        City          ProjectName            Name               Color     OtherData
-----   ------- ---------  -------        ----          -----------            ----               -----     ---------
Charles Contoso 2022-01-25 FakeStreet 123 San Francisco Sacramento Expansion   ProductA           Lemon     OtherData
Harvey  Specter 2022-01-25 NotAFake 123   San Diego     North Dakota Expansion ProductA, ProductB Red, Blue OtherData


问:
Redim Preserve VBA Alternatives

Background

I just read a comment on this question that states that Redim Preserve is expensive and should be avoided. I use Redim Preserve in many scenarios, let us say for example to save field names from a PT that meet some specific criteria to use them later on with an API for Access/Selenium/XlWings,etc. where I need to access the elements in the array at different times, thus not looping in the original sheet(s) where PT(s) are; I use them to save data that came outside Excel too. This is to save the time to redo verification/processes and everything that was considered by saving the array in the first place.

Research/thoughts

I have seen that a similar question was asked at VB.net where they  suggest List(Of Variable) but I do not think this may be achieved within Excel. I Erase them once they are not longer needed too. In addition, where it is possible, I try to use dictionaries instead of arrays, but it may not be always the case where it is easier to go by index numbers and there is a need for array and not dictionaries. I was thinking that I may be able to create a sheet with the specified items instead of saving them to an array, but I do not see the benefit of doing so in terms of memory saving.

Question

What would be the best alternative to Redim Preserve in VBA?

答:
The intent of Ben's comment is that you should avoid excessive use of Preserve.

Where Arrays are a good design choice,  you can and should use them.  This is especially true when extracting data from an Excel sheet.

So, how to avoid excessive use of Preserve?

The need to Redim Preserve implies you are collecting data into an array, usually in a loop.  Redim without Preserve is pretty fast.

If you have sufficient info, calculate the required array size and ReDim it as that size once

If you don't have that info, Redim it to an oversize dimension.  Redim Preserve to the actual size once, after the loop

If you must Redim Preserve in the loop, do it infrequently in large chunks

Beware of premature optimisation.  If it works fast enough for your needs, maybe just leave it as is

Title: Redim Preserve VBA Alternatives


问:
Splitting Contents of a File
So I have a file with a list of users in the format like this:

michael:atbWfKL4etk4U:500:500:Michael Ferris:/home/michael:/bin/bash
abigail:&i4KZ5wmac566:501:501:Abigail Smith:/home/abigail:/bin/tcsh

What I need to do is just extract the passwords from the file which in this case are:
"atbWfKL4etk4U" and "&i4KZ5wmac566" and to store them into an array.

This is what I have so far:

```<code>public static void main(String[] args) throws IOException{

    // Create a scanner for keyboard input
    Scanner scan = new Scanner(System.in);

    // Prompt user to select a file to open
    System.out.print("Enter the path of the file: ");
    String filename = scan.nextLine();

    // Open the file
    File file = new File(filename);
    Scanner inputFile = new Scanner(file);

    // Create Array to store each user password in
    String[] passwords = {};

    // Close the file
    scan.close();
    inputFile.close();

}
</code>```

答:
```<code>public static void main(String[] args) throws IOException{

    // Create a scanner for keyboard input
    Scanner scan = new Scanner(System.in);

    // Prompt user to select a file to open
    System.out.print("Enter the path of the file: ");
    String filename = scan.nextLine();

    // Open the file
    File file = new File(filename);
    Scanner inputFile = new Scanner(file);

    List<String> passwords = new ArrayList<>();
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        String password = line.split(":")[1];
        passwords.add(password);
    }
    // Close the file
    scan.close();
    inputFile.close();
}
</code>```

If instead you rather store username and password (assuming the first token is the user name), create a Map instead of a List.

```<code>Map<String, String> passwordMap = new HashMap<>();
while (sc.hasNextLine()) {
   String line = sc.nextLine();
   String[] tokens = line.split(":");
    passwordMap.put(tokens[0], tokens[1]);
}
</code>```

Title: Splitting Contents of a File

Body:
So I have a file with a list of users in the format like this:

michael:atbWfKL4etk4U:500:500:Michael Ferris:/home/michael:/bin/bash
abigail:&i4KZ5wmac566:501:501:Abigail Smith:/home/abigail:/bin/tcsh

What I need to do is just extract the passwords from the file which in this case are:
"atbWfKL4etk4U" and "&i4KZ5wmac566" and to store them into an array.

This is what I have so far:

public static void main(String[] args) throws IOException{

    // Create a scanner for keyboard input
    Scanner scan = new Scanner(System.in);

    // Prompt user to select a file to open
    System.out.print("Enter the path of the file: ");
    String filename = scan.nextLine();

    // Open the file
    File file = new File(filename);
    Scanner inputFile = new Scanner(file);

    // Create Array to store each user password in
    String[] passwords = {};

    // Close the file
    scan.close();
    inputFile.close();

}

Body:
public static void main(String[] args) throws IOException{

    // Create a scanner for keyboard input
    Scanner scan = new Scanner(System.in);

    // Prompt user to select a file to open
    System.out.print("Enter the path of the file: ");
    String filename = scan.nextLine();

    // Open the file
    File file = new File(filename);
    Scanner inputFile = new Scanner(file);

    List<String> passwords = new ArrayList<>();
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        String password = line.split(":")[1];
        passwords.add(password);
    }
    // Close the file
    scan.close();
    inputFile.close();
}

If instead you rather store username and password (assuming the first token is the user name), create a Map instead of a List.

Map<String, String> passwordMap = new HashMap<>();
while (sc.hasNextLine()) {
   String line = sc.nextLine();
   String[] tokens = line.split(":");
    passwordMap.put(tokens[0], tokens[1]);
}


问:
JavaScript RegEx Negative Lookbehind Without Doing a Negative Lookbehind in SuiteScript 2.x
I've put together a function in a custom module to handle trying to do a date/time formatting using the templates presented by NetSuite from the company preferences. However, I've had some trouble with handling the full name of the month and the hour in 12 hour format. If I use a negative lookbehind, it works just fine, but the problem is that it only works in scripts using 2.1, and there are too many in 2.0 to go around updating everything that needs this function from 2.0 to 2.1.

For example, these particular time templates:

```<code>Month D, YYYY
h:mm
</code>```

The first will have proper output like:

```<code>February 11, 2022
</code>```

But the second will have erroneous output:

```<code>h:15
</code>```

I'm using the following RegEx to match the hour placeholder:

```<code>/^(?!nt)h/
</code>```

And I know this works better where I can use it:

```<code>/(?<!nt)h/
</code>```

I've tried searching around for a way to handle matching the "h" where it's not preceded by "nt", but they all keep pointing to the use of a negative lookbehinds to handle it, or are a bit unclear as to exactly how it's being done.

EDIT

Just to reduce confusion, the following are formats that could also be passed in to the function and need to be handled correctly:

```<code>YYYY/DD/MM h:m:s
MONTH DD, YYYY H-mm-ss
YYYYDDMMhms
YYYYDDMM-HHmmss
</code>```

There's no one specific date/time template that can be passed in, so there's a specific need to be able to find H/h without it being a part of the word 'Month'.

答:
You might use a capture group instead to capture what you want to keep, and match what you want to get out of the way.

The pattern matches nth that you don't want, and captures a h char.

In the code you could check if group 1 is present.

```<code>nth|(h)
</code>```

Regex demo

For example in Javascript

const regex = /nth|(h)/gi;
const str = `Month D, YYYY
h:mm

February 11, 2022
h:15
YYYY/DD/MM h:m:s
MONTH DD, YYYY H-mm-ss
YYYYDDMMhms
YYYYDDMM-HHmmss`;

const result = str.replace(regex, function(m, g1) {
  return g1 !== undefined ? "[" + g1 + "]" : m;
});
console.log(result);```

Body:
I've put together a function in a custom module to handle trying to do a date/time formatting using the templates presented by NetSuite from the company preferences. However, I've had some trouble with handling the full name of the month and the hour in 12 hour format. If I use a negative lookbehind, it works just fine, but the problem is that it only works in scripts using 2.1, and there are too many in 2.0 to go around updating everything that needs this function from 2.0 to 2.1.

For example, these particular time templates:

Month D, YYYY
h:mm

The first will have proper output like:

February 11, 2022

But the second will have erroneous output:

h:15

I'm using the following RegEx to match the hour placeholder:

/^(?!nt)h/

And I know this works better where I can use it:

/(?<!nt)h/

I've tried searching around for a way to handle matching the "h" where it's not preceded by "nt", but they all keep pointing to the use of a negative lookbehinds to handle it, or are a bit unclear as to exactly how it's being done.

EDIT

Just to reduce confusion, the following are formats that could also be passed in to the function and need to be handled correctly:

YYYY/DD/MM h:m:s
MONTH DD, YYYY H-mm-ss
YYYYDDMMhms
YYYYDDMM-HHmmss

There's no one specific date/time template that can be passed in, so there's a specific need to be able to find H/h without it being a part of the word 'Month'.

Body:
You might use a capture group instead to capture what you want to keep, and match what you want to get out of the way.

The pattern matches nth that you don't want, and captures a h char.

In the code you could check if group 1 is present.

nth|(h)

Regex demo

For example in Javascript

const regex = /nth|(h)/gi;
const str = `Month D, YYYY
h:mm

February 11, 2022
h:15
YYYY/DD/MM h:m:s
MONTH DD, YYYY H-mm-ss
YYYYDDMMhms
YYYYDDMM-HHmmss`;

const result = str.replace(regex, function(m, g1) {
  return g1 !== undefined ? "[" + g1 + "]" : m;
});
console.log(result);


问:
Why wont my input boxplot code not work for my matrix?
I am having issues getting a plot for my dataframe. Attached below is my sample matrix dataframe. This class is confirmed a dataframe.

Dataframe (10 rows, 59 columns originally)

I have originally tried to create a plot using facet_grid, with poor results.
(Error: At least one layer must contain all faceting variables: x.

Plot is missing x

Layer 1 is missing x)

Instead, I decided to simplify it and create a box plot with everything on 1 graph. However, my graph looked like this:
ugly graph

My simple plot code is below; does anyone know why things are plotted poorly? Any insight is helpful. This is my first post, so I hope things are formatted correctly.

ggplot(newdf, aes(x, y, fill = x))+ geom_boxplot()

The end goal would be a boxplot shown for each gene with the observations of the individuals within each box. I am following this example:example

答:
First of all, when following examples you should make sure to change the variable's names in them to your variable's names.

In ggplot(newdf, aes(x, y, fill = x))+ geom_boxplot(), the errors probably come from the fact that you have neither an x or y column in newdf.
Or if you do, they aren't what you need for your goal.

The end goal being

a boxplot shown for each gene with the observations of the individuals within each box

your x variabe needs to be a column in which you have the genes names and y a column with the value of the observation for these gene.

In other word, you need to reformat your data.frame into a long format (right now you have what's called a wide format).

There many ways to do so, a simple one with base R is to repeat the name of each column times the number of row for the gene column and then unlisting your data.frame into the value column like so :

```<code># needed a a data.frame so made a fake one to illustrate :
newdf <- data.frame(gene1 = runif(10, ), gene2 = runif(10), gene3 = runif(10))
# this convert your data.frame from wide to long
newdf.long <- data.frame(
  gene = rep(names(newdf), each=nrow(newdf)),
  value = unlist(newdf),
  row.names = NULL
)
</code>```

Then, you need to make sure to use the right variable's name when building your ggplot :

```<code>ggplot(newdf.long, aes(x = gene, y = value, fill = gene)) + geom_boxplot()
</code>```

Body:
First of all, when following examples you should make sure to change the variable's names in them to your variable's names.

In ggplot(newdf, aes(x, y, fill = x))+ geom_boxplot(), the errors probably come from the fact that you have neither an x or y column in newdf.
Or if you do, they aren't what you need for your goal.

The end goal being

a boxplot shown for each gene with the observations of the individuals within each box

your x variabe needs to be a column in which you have the genes names and y a column with the value of the observation for these gene.

In other word, you need to reformat your data.frame into a long format (right now you have what's called a wide format).

There many ways to do so, a simple one with base R is to repeat the name of each column times the number of row for the gene column and then unlisting your data.frame into the value column like so :

# needed a a data.frame so made a fake one to illustrate :
newdf <- data.frame(gene1 = runif(10, ), gene2 = runif(10), gene3 = runif(10))
# this convert your data.frame from wide to long
newdf.long <- data.frame(
  gene = rep(names(newdf), each=nrow(newdf)),
  value = unlist(newdf),
  row.names = NULL
)

Then, you need to make sure to use the right variable's name when building your ggplot :

ggplot(newdf.long, aes(x = gene, y = value, fill = gene)) + geom_boxplot()


问:
Copying a spreadsheet copies all linked files as well
I want to be able to only copy the spreadsheet and all it's sheets along with all defined sheet names, when I utilize the library method:

```<code>spreadSheet.copy(newSSName);
</code>```

Or,

```<code>myFile.makeCopy(newNameOfFile);
</code>```

Currently these methods copy all linked forms and scripts used in the forms. This is an unnecessary side effect for what I need and will result in a large mess in the Drive folder. Is there a way to do this quickly and efficiently without copying cell by cell, sheet by sheet? Or is that the only option?

Thanks.

答:
Copy Spreadsheet to Destination Folder without copying Scripts

```<code>function copyspreadsheetwithoutgoogleappsscript() {
  const ssid = "";//source spreadsheet id
  const fldrid = "";//destination folder id
  Drive.Files.update({ parents: [{ id: fldrid }] }, Sheets.Spreadsheets.create(Sheets.Spreadsheets.get(ssid,{fields:"sheets,namedRanges,properties"})).spreadsheetId);
}
</code>```

for sub properties use /

Working With Field Masks

available fields between spreadsheets and spreadsheet properties

Can also do it using the API endpoint if you wish:

```<code>function copyssurl() {
  const ssid = "";
  const dfldrid = "";
  const url = `https://sheets.googleapis.com/v4/spreadsheets/${ssid}?fields=(sheets%2CnamedRanges%2Cproperties)`;
  const options = { "method": "get", "muteHttpExceptions": true, "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };
  const resp = UrlFetchApp.fetch(url,options);
  const obj = JSON.parse(resp.getContentText());
  Drive.Files.update({ parents: [{ id: dfldrid }] }, Sheets.Spreadsheets.create(obj).spreadsheetId);
}
</code>```

%2C is a comma

%2F is a forward slash

Body:
I want to be able to only copy the spreadsheet and all it's sheets along with all defined sheet names, when I utilize the library method:

spreadSheet.copy(newSSName);

Or,

myFile.makeCopy(newNameOfFile);

Currently these methods copy all linked forms and scripts used in the forms. This is an unnecessary side effect for what I need and will result in a large mess in the Drive folder. Is there a way to do this quickly and efficiently without copying cell by cell, sheet by sheet? Or is that the only option?

Thanks.

Body:
Copy Spreadsheet to Destination Folder without copying Scripts

function copyspreadsheetwithoutgoogleappsscript() {
  const ssid = "";//source spreadsheet id
  const fldrid = "";//destination folder id
  Drive.Files.update({ parents: [{ id: fldrid }] }, Sheets.Spreadsheets.create(Sheets.Spreadsheets.get(ssid,{fields:"sheets,namedRanges,properties"})).spreadsheetId);
}

for sub properties use /

Working With Field Masks

available fields between spreadsheets and spreadsheet properties

Can also do it using the API endpoint if you wish:

function copyssurl() {
  const ssid = "";
  const dfldrid = "";
  const url = `https://sheets.googleapis.com/v4/spreadsheets/${ssid}?fields=(sheets%2CnamedRanges%2Cproperties)`;
  const options = { "method": "get", "muteHttpExceptions": true, "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };
  const resp = UrlFetchApp.fetch(url,options);
  const obj = JSON.parse(resp.getContentText());
  Drive.Files.update({ parents: [{ id: dfldrid }] }, Sheets.Spreadsheets.create(obj).spreadsheetId);
}

%2C is a comma

%2F is a forward slash


问:
COUNTIFS w/ Multiple Criteria in Same Column
I'm trying to count instances of letters (like letters C through Z, excluding RR) within the same column if they are listed next to a name. Here's my sample Google Sheet that you can edit.

I'm trying to insert the formula in cell F3 that is highlighted yellow. So far I have...

```<code>=arrayformula(SUM(COUNTIFS(A2:A,{"C","D","E","F","G"},C2:C,E3:E)))
</code>```

It seems like what I have should work, but it's giving me a #VALUE error, saying, "ARRAY arguments to COUNTIFS are of different size".

It seems like REGEXMATCH could be used inside the COUNTIF formula to make it easier to restrict the search to the range of letters I need, but not sure how to construct the formula.

Thanks for your help!

UPDATE
This formula below works but only for column A. I actually need to specify a different range of letters to be counted in column B and totaled in column K.

```<code>=QUERY(A2:C,"select C,count(A) where A matches 'C|D|E|F|G|H|I|J|K' group by C label count(A)''", 0)
</code>```

Seems like this post almost answers it.

答:
Current progress:

```<code>={QUERY(A2:C,"select C,count(A) where A matches 'C|D|E|F|G|H|I|J|K' and A is not null group by C label count(A)''", 0),QUERY(A2:C,"select count(B) where B matches 'F|G|H|I|J|K' and B is not null group by C label count(B)''", 0)}
</code>```

As we have discussed / tested on your sample sheet. This should work as close as possible to the data that you would want to filter/display.

Body:
I'm trying to count instances of letters (like letters C through Z, excluding RR) within the same column if they are listed next to a name. Here's my sample Google Sheet that you can edit.

I'm trying to insert the formula in cell F3 that is highlighted yellow. So far I have...

=arrayformula(SUM(COUNTIFS(A2:A,{"C","D","E","F","G"},C2:C,E3:E)))

It seems like what I have should work, but it's giving me a #VALUE error, saying, "ARRAY arguments to COUNTIFS are of different size".

It seems like REGEXMATCH could be used inside the COUNTIF formula to make it easier to restrict the search to the range of letters I need, but not sure how to construct the formula.

Thanks for your help!

UPDATE
This formula below works but only for column A. I actually need to specify a different range of letters to be counted in column B and totaled in column K.

=QUERY(A2:C,"select C,count(A) where A matches 'C|D|E|F|G|H|I|J|K' group by C label count(A)''", 0)

Seems like this post almost answers it.

Body:
Current progress:

={QUERY(A2:C,"select C,count(A) where A matches 'C|D|E|F|G|H|I|J|K' and A is not null group by C label count(A)''", 0),QUERY(A2:C,"select count(B) where B matches 'F|G|H|I|J|K' and B is not null group by C label count(B)''", 0)}

As we have discussed / tested on your sample sheet. This should work as close as possible to the data that you would want to filter/display.


问:
Open/close SVG animation not working in Safari
I made this little open and close SVG animation as a react component. It is working ok in Chrome but in Safari I can't seem to understand why it doesn't work.

I know we aren't supposed to but a useRef reference inside a SVG  group but it seems like transform command is passed down to children ok.

I'm hoping one of you fine folks can get me back on the road again.

```<code>import React, {useRef, useState, useEffect} from 'react';
import { useSelector } from 'react-redux';
import './snap.styles.scss';

const Snap = ({className}) => {
    const {loading, product} = useSelector(state => state.productDetails);
    const [angle, setAngle] = useState(-8)
    const ref = useRef();
    const finalAngle = -20;

    const transformValue = `translate(820px, 350px) rotate(${angle}deg) translate(-820px, -350px)`

    const animation = () => {
        let opened=false;
        let closing = false;
        let currentAngle = -8;
        const breakpoint = -20;
        const intervalId = setInterval(()=> {

            setAngle(currentAngle);

            if(currentAngle < 0 && !opened) {
                console.log('0 to open')
                currentAngle += .5;
            }
            else if (!closing) {
                console.log('open to closing')

                currentAngle -= .5;
                opened=true;
                if(currentAngle < -19) closing = true;
            }
            else if (closing) {
                console.log('closing till closed')

                currentAngle += .5;
                if(currentAngle > -9) clearInterval(intervalId);
            }
        }, 13)
    }

useEffect(()=> {
    if(!loading) animation();
}, [product])

useEffect(()=>{
    ref.current.style.transform = transformValue
}, [angle])

    return <div>
        <svg className='snap-svg' xmlns="http://www.w3.org/2000/svg" viewBox="250 230 300 300">
            <defs>
                <g id='snap1'>
                    <path d="M894.84,432.54a1.48,1.48,0,0,0,.1-.36l1-6.21a1.49,1.49,0,0,0,0-.21v-6.18a1.41,1.41,0,0,0-.07-.41L894,413.05a1.33,1.33,0,0,0-.16-.34l-3.28-5.17a2,2,0,0,0-.27-.31l-6.84-5.86L878.08,397a1.31,1.31,0,0,0-.36-.21L863,390.89l-.11,0L845,385.38l-.09,0-24.87-6a.51.51,0,0,0-.17,0L788,375.87h-.09l-58-2.5H670.38l-45.46,2.5-83.5,7-156,21.22L315.5,414.14a1.38,1.38,0,0,1-1.58-1.37h0a1.39,1.39,0,0,0-1.61-1.38l-7.89,1.23-43.26,6.71a1.48,1.48,0,0,0-.46.16l-9.63,5.29a1.46,1.46,0,0,0-.28.21l-9.33,8.84-.08.08-3.9,4.39a1,1,0,0,0-.12.15l-3.92,5.89-.05.06-9,12-23.94,32.41a1.07,1.07,0,0,1-.14.16L193,496.3l-.14.13L185,502.28l-.24.15-8.37,3.94-9.8,4.4a1.06,1.06,0,0,1-.43.12l-10.21,1h-9.92a1.43,1.43,0,0,1-.29,0l-9.24-1.95a1.41,1.41,0,0,1-.22-.06l-8.8-3.42-.18-.09-6.91-3.95-6.37-3.43a1.38,1.38,0,0,1-.25-.17l-6.88-5.9L100.51,487a1.63,1.63,0,0,1-.17-.2l-5.42-7.39-5.37-7.8a1.35,1.35,0,0,1-.2-.44l-2.92-11.19,0-.15-1.47-10.32a1.41,1.41,0,0,1,0-.2V439a1.27,1.27,0,0,1,0-.2L86.4,429a1.16,1.16,0,0,1,0-.18l2.94-10.3a1,1,0,0,1,.09-.22l5.41-11.32a.64.64,0,0,1,.08-.14L101.82,396a1.49,1.49,0,0,1,.23-.28L113.8,385a1.1,1.1,0,0,1,.25-.19l11.28-6.37.18-.09,12.66-4.87a1.43,1.43,0,0,1,.5-.09h16.12l.25,0,13.82,2.47.11,0,9.33,2.46a.83.83,0,0,1,.22.08l9.79,4.4.2.11,8.85,5.9.1.08,14.92,11.93.06.05,14.44,12.94.07.08,34,35.46" transform="translate(-74.92 -73.37)"/>
                    <path d="M344.42,381.87" transform="translate(-74.92 -73.37)"/>
                    <path d="M249.92,393.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M270.92,389.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M291.92,385.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M312.92,382.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M341.92,384.87" transform="translate(-74.92 -73.37)"/>
                    <g ref={ref} className='snap1__arm'>
                        <path d="M356.72,297.78l9.91,64.7,10.69,34.38,16,27.2,9.61,8.8,10.46,6.92,17.26,8.63,17.79,5.68,25.17,7,25.11,4.43,58.6,10.33L609,482.39,681.11,488l46.61.6,46-1.54,24.54-3.8,21.66-4.81L855.74,468,874,459.56l8.29-6.66,4.4-4.81,3.41-5,2.12-6.23,1.13-6.4" transform="translate(-74.92 -73.37)"/>
                        <path d="M323.27,357.88" transform="translate(-74.92 -73.37)"/>
                        <path d="M353.73,300.3l-5.49,60" transform="translate(-74.92 -73.37)"/>
                    </g>
                </g>
            </defs>

            <use xlinkHref='#snap1' className="snap1" />

        </svg>
  </div>;
};

export default Snap;

</code>```

Body:
I made this little open and close SVG animation as a react component. It is working ok in Chrome but in Safari I can't seem to understand why it doesn't work.

I know we aren't supposed to but a useRef reference inside a SVG  group but it seems like transform command is passed down to children ok.

I'm hoping one of you fine folks can get me back on the road again.

import React, {useRef, useState, useEffect} from 'react';
import { useSelector } from 'react-redux';
import './snap.styles.scss';

const Snap = ({className}) => {
    const {loading, product} = useSelector(state => state.productDetails);
    const [angle, setAngle] = useState(-8)
    const ref = useRef();
    const finalAngle = -20;

    const transformValue = `translate(820px, 350px) rotate(${angle}deg) translate(-820px, -350px)`

    const animation = () => {
        let opened=false;
        let closing = false;
        let currentAngle = -8;
        const breakpoint = -20;
        const intervalId = setInterval(()=> {

            setAngle(currentAngle);

            if(currentAngle < 0 && !opened) {
                console.log('0 to open')
                currentAngle += .5;
            }
            else if (!closing) {
                console.log('open to closing')

                currentAngle -= .5;
                opened=true;
                if(currentAngle < -19) closing = true;
            }
            else if (closing) {
                console.log('closing till closed')

                currentAngle += .5;
                if(currentAngle > -9) clearInterval(intervalId);
            }
        }, 13)
    }

useEffect(()=> {
    if(!loading) animation();
}, [product])

useEffect(()=>{
    ref.current.style.transform = transformValue
}, [angle])

    return

        <svg className='snap-svg' xmlns="http://www.w3.org/2000/svg" viewBox="250 230 300 300">
            <defs>
                <g id='snap1'>
                    <path d="M894.84,432.54a1.48,1.48,0,0,0,.1-.36l1-6.21a1.49,1.49,0,0,0,0-.21v-6.18a1.41,1.41,0,0,0-.07-.41L894,413.05a1.33,1.33,0,0,0-.16-.34l-3.28-5.17a2,2,0,0,0-.27-.31l-6.84-5.86L878.08,397a1.31,1.31,0,0,0-.36-.21L863,390.89l-.11,0L845,385.38l-.09,0-24.87-6a.51.51,0,0,0-.17,0L788,375.87h-.09l-58-2.5H670.38l-45.46,2.5-83.5,7-156,21.22L315.5,414.14a1.38,1.38,0,0,1-1.58-1.37h0a1.39,1.39,0,0,0-1.61-1.38l-7.89,1.23-43.26,6.71a1.48,1.48,0,0,0-.46.16l-9.63,5.29a1.46,1.46,0,0,0-.28.21l-9.33,8.84-.08.08-3.9,4.39a1,1,0,0,0-.12.15l-3.92,5.89-.05.06-9,12-23.94,32.41a1.07,1.07,0,0,1-.14.16L193,496.3l-.14.13L185,502.28l-.24.15-8.37,3.94-9.8,4.4a1.06,1.06,0,0,1-.43.12l-10.21,1h-9.92a1.43,1.43,0,0,1-.29,0l-9.24-1.95a1.41,1.41,0,0,1-.22-.06l-8.8-3.42-.18-.09-6.91-3.95-6.37-3.43a1.38,1.38,0,0,1-.25-.17l-6.88-5.9L100.51,487a1.63,1.63,0,0,1-.17-.2l-5.42-7.39-5.37-7.8a1.35,1.35,0,0,1-.2-.44l-2.92-11.19,0-.15-1.47-10.32a1.41,1.41,0,0,1,0-.2V439a1.27,1.27,0,0,1,0-.2L86.4,429a1.16,1.16,0,0,1,0-.18l2.94-10.3a1,1,0,0,1,.09-.22l5.41-11.32a.64.64,0,0,1,.08-.14L101.82,396a1.49,1.49,0,0,1,.23-.28L113.8,385a1.1,1.1,0,0,1,.25-.19l11.28-6.37.18-.09,12.66-4.87a1.43,1.43,0,0,1,.5-.09h16.12l.25,0,13.82,2.47.11,0,9.33,2.46a.83.83,0,0,1,.22.08l9.79,4.4.2.11,8.85,5.9.1.08,14.92,11.93.06.05,14.44,12.94.07.08,34,35.46" transform="translate(-74.92 -73.37)"/>
                    <path d="M344.42,381.87" transform="translate(-74.92 -73.37)"/>
                    <path d="M249.92,393.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M270.92,389.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M291.92,385.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M312.92,382.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M341.92,384.87" transform="translate(-74.92 -73.37)"/>
                    <g ref={ref} className='snap1__arm'>
                        <path d="M356.72,297.78l9.91,64.7,10.69,34.38,16,27.2,9.61,8.8,10.46,6.92,17.26,8.63,17.79,5.68,25.17,7,25.11,4.43,58.6,10.33L609,482.39,681.11,488l46.61.6,46-1.54,24.54-3.8,21.66-4.81L855.74,468,874,459.56l8.29-6.66,4.4-4.81,3.41-5,2.12-6.23,1.13-6.4" transform="translate(-74.92 -73.37)"/>
                        <path d="M323.27,357.88" transform="translate(-74.92 -73.37)"/>
                        <path d="M353.73,300.3l-5.49,60" transform="translate(-74.92 -73.37)"/>
                    </g>
                </g>
            </defs>

            <use xlinkHref='#snap1' className="snap1" />

        </svg>

;
};

export default Snap;

Body:
I'll leave this post for posterity but I abandoned the 'defs' into 'use' idiom and went straight up 'svg' immediate injection. This made it work in safari.

Need to research why this is the case but I am reading a book on the subject and will fill in blanks as I go. Would appreciate if anyone wants to shed light on this.

The fix here was to change return block to :

return <svg className='snap1' xmlns="http://www.w3.org/2000/svg" viewBox="250 230 300 300">
                    <path d="M894.84,432.54a1.48,1.48,0,0,0,.1-.36l1-6.21a1.49,1.49,0,0,0,0-.21v-6.18a1.41,1.41,0,0,0-.07-.41L894,413.05a1.33,1.33,0,0,0-.16-.34l-3.28-5.17a2,2,0,0,0-.27-.31l-6.84-5.86L878.08,397a1.31,1.31,0,0,0-.36-.21L863,390.89l-.11,0L845,385.38l-.09,0-24.87-6a.51.51,0,0,0-.17,0L788,375.87h-.09l-58-2.5H670.38l-45.46,2.5-83.5,7-156,21.22L315.5,414.14a1.38,1.38,0,0,1-1.58-1.37h0a1.39,1.39,0,0,0-1.61-1.38l-7.89,1.23-43.26,6.71a1.48,1.48,0,0,0-.46.16l-9.63,5.29a1.46,1.46,0,0,0-.28.21l-9.33,8.84-.08.08-3.9,4.39a1,1,0,0,0-.12.15l-3.92,5.89-.05.06-9,12-23.94,32.41a1.07,1.07,0,0,1-.14.16L193,496.3l-.14.13L185,502.28l-.24.15-8.37,3.94-9.8,4.4a1.06,1.06,0,0,1-.43.12l-10.21,1h-9.92a1.43,1.43,0,0,1-.29,0l-9.24-1.95a1.41,1.41,0,0,1-.22-.06l-8.8-3.42-.18-.09-6.91-3.95-6.37-3.43a1.38,1.38,0,0,1-.25-.17l-6.88-5.9L100.51,487a1.63,1.63,0,0,1-.17-.2l-5.42-7.39-5.37-7.8a1.35,1.35,0,0,1-.2-.44l-2.92-11.19,0-.15-1.47-10.32a1.41,1.41,0,0,1,0-.2V439a1.27,1.27,0,0,1,0-.2L86.4,429a1.16,1.16,0,0,1,0-.18l2.94-10.3a1,1,0,0,1,.09-.22l5.41-11.32a.64.64,0,0,1,.08-.14L101.82,396a1.49,1.49,0,0,1,.23-.28L113.8,385a1.1,1.1,0,0,1,.25-.19l11.28-6.37.18-.09,12.66-4.87a1.43,1.43,0,0,1,.5-.09h16.12l.25,0,13.82,2.47.11,0,9.33,2.46a.83.83,0,0,1,.22.08l9.79,4.4.2.11,8.85,5.9.1.08,14.92,11.93.06.05,14.44,12.94.07.08,34,35.46" transform="translate(-74.92 -73.37)"/>
                    <path d="M344.42,381.87" transform="translate(-74.92 -73.37)"/>
                    <path d="M249.92,393.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M270.92,389.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M291.92,385.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M312.92,382.87l9,64" transform="translate(-74.92 -73.37)"/>
                    <path d="M341.92,384.87" transform="translate(-74.92 -73.37)"/>
                    <g ref={ref} className='snap1__arm'>
                        <path d="M356.72,297.78l9.91,64.7,10.69,34.38,16,27.2,9.61,8.8,10.46,6.92,17.26,8.63,17.79,5.68,25.17,7,25.11,4.43,58.6,10.33L609,482.39,681.11,488l46.61.6,46-1.54,24.54-3.8,21.66-4.81L855.74,468,874,459.56l8.29-6.66,4.4-4.81,3.41-5,2.12-6.23,1.13-6.4" transform="translate(-74.92 -73.37)"/>
                        <path d="M323.27,357.88" transform="translate(-74.92 -73.37)"/>
                        <path d="M353.73,300.3l-5.49,60" transform="translate(-74.92 -73.37)"/>
                    </g>

        </svg>  ;


问:
PHP, JSON and \u-somethings
I'm using php 5.2. My file and db table are utf8.

when i insert a column with json_encoded data in it, it converts non-ascii chars into \u-something. ok. when i json_decode the data those \u-somethings are still there!

wasn't json_decode supposed to convert back to the normal chars when displaying on a utf8 page. For example, instead of f\u00f6tter, it should display fötter. do i have to use another function for conversion?

答:
i know this is an old question but the answer did not really answer the question for me.

eventually, i was able to get what i wanted using the JSON_UNESCAPED_UNICODE flag.

$output = json_encode($input, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

https://www.php.net/manual/en/function.json-encode.php

caveat:  this only works if you are able to store utf8 in your database; you said your table is utf8 so that should be ok.  i was not able to find a way to convert the \u strings back at decode time, so encoding it as unescaped utf8 is what worked for me.

also, if you're using PHP 7.1+ (your post said 5.2 but that was a long time ago) then you may want to add the JSON_UNESCAPED_LINE_TERMINATORS flag as well)

Title: PHP, JSON and \u-somethings


问:
For which reason this Angular Service is not working?
I created an Angular app with controller. I can successfully use the controller (with Postman, see screenshot below).

At the fronted I implemented a new component including service to show the data from controller (see code below). The service is not working. No data are shown at the application.

I made a breakpoint in feedback.service.ts/getFeedbacks() and in feedback.component.ts/ngOnInit(). Both are reached.

I mad a breakpoint at my controller and this one is never reached (except using postman).

Why doesn't the data from the controller reach the GUI?

feedback.component.html:

Feedback List:

       {{feedback.comment}}

Count: {{feedbacks.length}}

```
<p>feedback.component.ts:</p>
```import { Component, OnInit } from '@angular/core';
import { Feedback } from './feedback';
import { FeedbackService } from './feedback.service';

@Component({
  selector: 'app-feedback',
  templateUrl: './feedback.component.html',
  styleUrls: ['./feedback.component.css']
})
export class FeedbackComponent implements OnInit {
  feedbacks: Feedback[] = [];
    objects: any;

  constructor(private feedbackService: FeedbackService) { }

  ngOnInit(): void {
    this.feedbackService
      .getFeedbacks()
      .subscribe(feedbacks => this.feedbacks = feedbacks);
  }
}
```
<p>feedback.service.ts:</p>
```import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Feedback } from './feedback';

@Injectable({
  providedIn: 'root'
})
export class FeedbackService {

  constructor(private http: HttpClient) { }

  getFeedbacks(): Observable<Feedback[]> {
    let result: Observable<Feedback[]>;
    result = this.http.get<Feedback[]>('/feedback');
    return result;
  }
}
```
<p>feedback.ts:</p>
```export interface Feedback {
    id:      number;
    comment: string;
    userId:  number;
}
```
<p>app.modules.ts:</p>
```// other imports ...
import { FeedbackComponent } from './feedback/feedback.component';
import { FeedbackService } from './feedback/feedback.service';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    FeedbackComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: FeedbackComponent, pathMatch: 'full' }
    ]),
    BrowserAnimationsModule,
    MatToolbarModule
  ],
  providers: [FeedbackService],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

Screenshot from browser:

答:
My solution:

at the .NET 6 backend, Program.cs
add as first service:

builder.Services.AddCors(options => options.AddPolicy("TheCodeBuzzPolicy", builder =>
{
    builder.AllowAnyOrigin()
           .AllowAnyMethod()
           .AllowAnyHeader();
}));```
</div>
</div>
</p>
<p>then add after app.UseRouting():</p>
<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>app.UseCors("MyPolicy");
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireCors("TheCodeBuzzPolicy");

});</code>```

Body:
I created an Angular app with controller. I can successfully use the controller (with Postman, see screenshot below).

At the fronted I implemented a new component including service to show the data from controller (see code below). The service is not working. No data are shown at the application.

I made a breakpoint in feedback.service.ts/getFeedbacks() and in feedback.component.ts/ngOnInit(). Both are reached.

I mad a breakpoint at my controller and this one is never reached (except using postman).

Why doesn't the data from the controller reach the GUI?

feedback.component.html:

Feedback List:

       {{feedback.comment}}

Count: {{feedbacks.length}}

feedback.component.ts:

import { Component, OnInit } from '@angular/core';
import { Feedback } from './feedback';
import { FeedbackService } from './feedback.service';

@Component({
  selector: 'app-feedback',
  templateUrl: './feedback.component.html',
  styleUrls: ['./feedback.component.css']
})
export class FeedbackComponent implements OnInit {
  feedbacks: Feedback[] = [];
    objects: any;

  constructor(private feedbackService: FeedbackService) { }

  ngOnInit(): void {
    this.feedbackService
      .getFeedbacks()
      .subscribe(feedbacks => this.feedbacks = feedbacks);
  }
}

feedback.service.ts:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Feedback } from './feedback';

@Injectable({
  providedIn: 'root'
})
export class FeedbackService {

  constructor(private http: HttpClient) { }

  getFeedbacks(): Observable<Feedback[]> {
    let result: Observable<Feedback[]>;
    result = this.http.get<Feedback[]>('/feedback');
    return result;
  }
}

feedback.ts:

export interface Feedback {
    id:      number;
    comment: string;
    userId:  number;
}

app.modules.ts:

// other imports ...
import { FeedbackComponent } from './feedback/feedback.component';
import { FeedbackService } from './feedback/feedback.service';

@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent,
    HomeComponent,
    FeedbackComponent
  ],
  imports: [
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    RouterModule.forRoot([
      { path: '', component: FeedbackComponent, pathMatch: 'full' }
    ]),
    BrowserAnimationsModule,
    MatToolbarModule
  ],
  providers: [FeedbackService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Screenshot from browser:

Body:
My solution:

at the .NET 6 backend, Program.cs
add as first service:

builder.Services.AddCors(options => options.AddPolicy("TheCodeBuzzPolicy", builder =>
{
    builder.AllowAnyOrigin()
           .AllowAnyMethod()
           .AllowAnyHeader();
}));

then add after app.UseRouting():

app.UseCors("MyPolicy");
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers().RequireCors("TheCodeBuzzPolicy");

});


问:
How can I get my min and max function to print my error message properly?
This is the prompt we were given to find the function needed:

A function that prompts the user for the minimum value and returns it
to the calling statement. Function to also deal with range checking to
make sure that the minimum value provided is greater than 0

Here's my code below however it doesn't print out the error message when I enter a minimum value higher than the maximum value.

```<code>def get_min():
       return int(input("What's your minimum value?"))

def min_Check(get_min):
    if (get_min >= 0):
      return print("ERROR. Minimum should be greater than 0")
else:
      return get_min

def get_max():
        return int(input("What's your maximun value?"))

def max_Check(get_min):
   if (get_max <= get_min):
    return print(f"ERROR. Maximum value must be greater {min}")
else:
    return max

min_value = get_min()
max_value = get_max()
get_check1 = min_Check(get_min)
get_check2 = max_Check(get_min)
</code>```

答:
note the difference :

1- you make a wrong condition in min_check function

2- you don't use () when you use the output of the two get function in conditions

```<code>def get_min():
    return int(input("What's your minimum value?"))
def min_Check(get_min):
    if (get_min() <= 0):
        return print("ERROR. Minimum should be greater than 0")
    else:
        return get_min
def get_max():
    return int(input("What's your maximun value?"))
def max_Check(get_min):
    if (get_max() <= get_min()):
        return print(f"ERROR. Maximum value must be greater {min}")
    else:
        return max
min_Check(get_min)
max_Check(get_min)

</code>```

Body:
This is the prompt we were given to find the function needed:

A function that prompts the user for the minimum value and returns it
to the calling statement. Function to also deal with range checking to
make sure that the minimum value provided is greater than 0

Here's my code below however it doesn't print out the error message when I enter a minimum value higher than the maximum value.

def get_min():
       return int(input("What's your minimum value?"))

def min_Check(get_min):
    if (get_min >= 0):
      return print("ERROR. Minimum should be greater than 0")
else:
      return get_min

def get_max():
        return int(input("What's your maximun value?"))

def max_Check(get_min):
   if (get_max <= get_min):
    return print(f"ERROR. Maximum value must be greater {min}")
else:
    return max

min_value = get_min()
max_value = get_max()
get_check1 = min_Check(get_min)
get_check2 = max_Check(get_min)

Body:
note the difference :

1- you make a wrong condition in min_check function

2- you don't use () when you use the output of the two get function in conditions

def get_min():
    return int(input("What's your minimum value?"))
def min_Check(get_min):
    if (get_min() <= 0):
        return print("ERROR. Minimum should be greater than 0")
    else:
        return get_min
def get_max():
    return int(input("What's your maximun value?"))
def max_Check(get_min):
    if (get_max() <= get_min()):
        return print(f"ERROR. Maximum value must be greater {min}")
    else:
        return max
min_Check(get_min)
max_Check(get_min)


问:
Is it possible to use jpackage to ship a javascript frontend java backend
From looking through the documentation for jpackage it doesn't seem there is any examples of how to use jpackage to bundle a javascript front end with a java backend. Is this possible?

答:
While the intention of JPackage is to package a Java application, there is a feature that allows you to split the job into two parts:

collect all required files and put them into a directory structure (called appdir)

wrap appdir into a platform dependent installable package

This has been done so you can customize the appdir if need be.

So you could start customizing the appdir by adding your frontend. As after package installation your java application is started as default, you would have to tweak something so the frontend gets started as well and starts talking to the backend. Ultimately you would also need a browser launched as well, pointing to your frontend.

All in all this would end up as a dirty hack, not giving you much advantage over conventional packing methods. So I tend to agree that your usecase is not feasible for JPackage.


问:
How to use Haskell's readFile function for multiple files
I understand a little bit about IO. I understand that you can use readFile to get the content of a file. For example like this:

```<code>main = do
    let inputFilePath = "C:\\Haskell\\myawesomeprogram\\files\\a.txt"
    content <- readFile inputFilePath
    print content
</code>```

Calling the program:

```<code>> runghc myawesomeprogram
"AAA"
</code>```

Awesome, that works! Now I want to read the content from multiple files.
I tried something like this:

```<code>files = ["C:\\Haskell\\myawesomeprogram\\files\\a.txt", "C:\\Haskell\\myawesomeprogram\\files\\b.txt","C:\\Haskell\\myawesomeprogram\\files\\c.txt"]

main :: IO ()
main = do
    filesContent <- readFiles files
    print filesContent

readFiles (x:xs) = do
    content <- readFile x
    content : readFiles xs
</code>```

This will give me the following error message:

```<code>myawesomeprogram.hs:6:21: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: filesContent <- readFiles files
      In the expression:
        do filesContent <- readFiles files
           print filesContent
      In an equation for `main':
          main
            = do filesContent <- readFiles files
                 print filesContent
  |
6 |     filesContent <- readFiles files
  |                     ^^^^^^^^^^^^^^^

myawesomeprogram.hs:9:1: error:
    Couldn't match type `IO' with `[]'
    Expected type: [FilePath] -> [String]
      Actual type: [FilePath] -> IO String
  |
9 | readFiles (x:xs) = do
  | ^^^^^^^^^^^^^^^^^^^^^^^...

myawesomeprogram.hs:11:5: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: content : readFiles xs
      In the expression:
        do content <- readFile x
           content : readFiles xs
      In an equation for `readFiles':
          readFiles (x : xs)
            = do content <- readFile x
                 content : readFiles xs
   |
11 |     content : readFiles xs
   |     ^^^^^^^^^^^^^^^^^^^^^^
</code>```

I'm doing something wrong, however, I can't see a way to do it right.
Can you do it the right way?

答:
readFiles xs is not a list, so you can't prepend an item to it. Instead, it's an action, which, when executed, would produce a list.

More specifically, the type of readFiles xs is IO [String] (IO is the type of executable actions), whereas a list would have type [String]. This is what the error message is telling you: cannot match type IO [String] with [String].

So to get the list, you have to execute the action, just like you're executing readFile

```<code>readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)
</code>```

Also note that readFiles doesn't know what to do when its argument is an empty list. You should get a warning about it at compile time, and if you don't fix it, you'll get a crash at runtime.

To fix, just add an equation for the empty list case:

```<code>readFiles [] = pure []
readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)
</code>```

Body:
I understand a little bit about IO. I understand that you can use readFile to get the content of a file. For example like this:

main = do
    let inputFilePath = "C:\\Haskell\\myawesomeprogram\\files\\a.txt"
    content <- readFile inputFilePath
    print content

Calling the program:

> runghc myawesomeprogram
"AAA"

Awesome, that works! Now I want to read the content from multiple files.
I tried something like this:

files = ["C:\\Haskell\\myawesomeprogram\\files\\a.txt", "C:\\Haskell\\myawesomeprogram\\files\\b.txt","C:\\Haskell\\myawesomeprogram\\files\\c.txt"]

main :: IO ()
main = do
    filesContent <- readFiles files
    print filesContent

readFiles (x:xs) = do
    content <- readFile x
    content : readFiles xs

This will give me the following error message:

myawesomeprogram.hs:6:21: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: filesContent <- readFiles files
      In the expression:
        do filesContent <- readFiles files
           print filesContent
      In an equation for `main':
          main
            = do filesContent <- readFiles files
                 print filesContent
  |
6 |     filesContent <- readFiles files
  |                     ^^^^^^^^^^^^^^^

myawesomeprogram.hs:9:1: error:
    Couldn't match type `IO' with `[]'
    Expected type: [FilePath] -> [String]
      Actual type: [FilePath] -> IO String
  |
9 | readFiles (x:xs) = do
  | ^^^^^^^^^^^^^^^^^^^^^^^...

myawesomeprogram.hs:11:5: error:
    * Couldn't match type `[]' with `IO'
      Expected type: IO String
        Actual type: [String]
    * In a stmt of a 'do' block: content : readFiles xs
      In the expression:
        do content <- readFile x
           content : readFiles xs
      In an equation for `readFiles':
          readFiles (x : xs)
            = do content <- readFile x
                 content : readFiles xs
   |
11 |     content : readFiles xs
   |     ^^^^^^^^^^^^^^^^^^^^^^

I'm doing something wrong, however, I can't see a way to do it right.
Can you do it the right way?

Body:
readFiles xs is not a list, so you can't prepend an item to it. Instead, it's an action, which, when executed, would produce a list.

More specifically, the type of readFiles xs is IO [String] (IO is the type of executable actions), whereas a list would have type [String]. This is what the error message is telling you: cannot match type IO [String] with [String].

So to get the list, you have to execute the action, just like you're executing readFile

readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)

Also note that readFiles doesn't know what to do when its argument is an empty list. You should get a warning about it at compile time, and if you don't fix it, you'll get a crash at runtime.

To fix, just add an equation for the empty list case:

readFiles [] = pure []
readFiles (x:xs) = do
    content <- readFile x
    theRest <- readFiles xs
    pure (content : theRest)


问:
Ordering a complex unordered list with javascript
I am looking for a way to sort a fairly complicated html unordered list using either standard javascript or jQuery.

Please view the HTML, the order needs to be alphabetical and based on the HTML found inside the ".keywordType span value" but needs to construct the order of the top level li (with the unique keyword_xxx). I've just pasted 2 of the list items out of dozens.

```<code><ul class="keywords">
    <li id="keyword_185">
        <div class="icon_keyword"></div>
        <input type="hidden" class="keywordLabel" value="More opening hours">
        <div class="data-wrapper">
            <div class="keywordType">
                <span class="oh">Payment methods</span>
            </div>
            <div class="keywordValue">
                <span id="keyword_185" class="oh">Credit Card, PayPal</span>
            </div>
        </div>
        <a class="edit" title="Edit keywords"></a>
        <a class="delete" title="Delete keywords"></a>
    </li>
    <li id="keyword_192">
        <div class="icon_keyword"></div>
        <input type="hidden" class="keywordLabel" value="Monday to Friday: 8:30am to 6:30pm Saturday: 9pm to 6:30pm Sunday: 10 - 4pm">
        <div class="data-wrapper">
            <div class="keywordType">
                <span class="oh">Opening Hours</span>
            </div>
            <div class="keywordValue">
                <span id="keyword_192" class="oh">Monday to Friday: 8:30am to 6:30pm<br>Saturday: 9pm to 6:30pm<br>Sunday: 10 - 4pm</span>
            </div>
        </div>
        <a class="edit" title="Edit keywords"></a>
        <a class="delete" title="Delete keywords"></a>
    </li>
</ul>
</code>```

Thanks

答:
Does this help?

```<code>var arr;
$('.keyword span').each( function( i, el){
    arr[i] = $(el).text();
});
arr.sort();
</code>```

I tested it on this question page, the code below orders the list of related questions in the right hand col.

```<code>var arr;
$('.question-hyperlink').each( function( i, el){
    arr[i] = $(el).text();
});
arr.sort();
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I am looking for a way to sort a fairly complicated html unordered list using either standard javascript or jQuery.

Please view the HTML, the order needs to be alphabetical and based on the HTML found inside the ".keywordType span value" but needs to construct the order of the top level li (with the unique keyword_xxx). I've just pasted 2 of the list items out of dozens.

        <input type="hidden" class="keywordLabel" value="More opening hours">

                Payment methods

                Credit Card, PayPal

        <input type="hidden" class="keywordLabel" value="Monday to Friday: 8:30am to 6:30pm Saturday: 9pm to 6:30pm Sunday: 10 - 4pm">

                Opening Hours

                Monday to Friday: 8:30am to 6:30pm
Saturday: 9pm to 6:30pm
Sunday: 10 - 4pm

Thanks

Body:
Does this help?

var arr;
$('.keyword span').each( function( i, el){
    arr[i] = $(el).text();
});
arr.sort();

I tested it on this question page, the code below orders the list of related questions in the right hand col.

var arr;
$('.question-hyperlink').each( function( i, el){
    arr[i] = $(el).text();
});
arr.sort();


问:
How find max of an inner element in a list of key, values?
I have a list of items as you see below. The values for each year key is a list of 10 items but to make it short, I am only showing the first couple of them. How I can find the maximum of all inner "count" values? I have looked at various approaches but none has worked so far and perhaps I am missing something here. For instance, I really like some of one liners here but they didnt work for me enter link description here

Just to clarify that data is the result of a nest on csv file and it meant to be used in d3 chart and preferably no import library other than standard ones.

```<code>data = [
         {'2015': values: [{key: '0', value: {count: 45}},{key: '1', value: {count: 3}}, ... ]},
         {'2016': values: [{key: '0', value: {count: 67}},{key: '1', value: {count: 0}}, ... ]},
     {'2017': values: [{key: '0', value: {count: 12}},{key: '1', value: {count: 8}}, ... ]}
        ]
</code>```

To better show how data looks like, here is the screen shot in case it helps clarification of the question.

答:
Your data structure appears to be incorrect. You cannot have { '2015': values: [...] }. This would be the equivalent of { KEY: VALUE: VALUE}. The browser appears to be inferring meaning from your code and creating an object out of it anyway, but it's not right.

You can do an object of objects and have named inner objects, like this:

```<code>data = {
    2015: {
        values: [
            { key: "0", value: { count: 45 } },
            { key: "1", value: { count: 3 } },
        ],
    },
    2016: {
        values: [
            { key: "0", value: { count: 67 } },
            { key: "1", value: { count: 0 } },
        ],
    },
    2017: {
        values: [
            { key: "0", value: { count: 12 } },
            { key: "1", value: { count: 8 } },
        ],
    },
};
</code>```

Or you can create an array of objects, like this:

```<code>data = [
    {
        year: 2015,
        values: [
            { key: "0", value: { count: 45 } },
            { key: "1", value: { count: 3 } },
        ],
    },
    {
        year: 2016,
        values: [
            { key: "0", value: { count: 67 } },
            { key: "1", value: { count: 0 } },
        ],
    },
    {
        year: 2017,
        values: [
            { key: "0", value: { count: 12 } },
            { key: "1", value: { count: 8 } },
        ],
    },
];
</code>```

How you get the highest count property depends on which data structure you use.

Using the array of objects, I would approach the problem like this:

```<code>// create a temp storage array to store "count" property of each
const countArray = [];

// iterate through the outer objects
for (const outerObject of data) {

    // iterate through the objects that are in the "values" array
    for (const innerObject of outerObject.values) {

        // push the "count" value to the array
        countArray.push(innerObject.value.count)
    }
}

// sort the array in place, with highest values first
countArray.sort((a, b) => b - a);

// display the result
console.log(countArray[0])
</code>```

You could do something similar for the object-of-objects data structure, but you'd need different syntax for that.

Body:
I have a list of items as you see below. The values for each year key is a list of 10 items but to make it short, I am only showing the first couple of them. How I can find the maximum of all inner "count" values? I have looked at various approaches but none has worked so far and perhaps I am missing something here. For instance, I really like some of one liners here but they didnt work for me enter link description here

Just to clarify that data is the result of a nest on csv file and it meant to be used in d3 chart and preferably no import library other than standard ones.

data = [
         {'2015': values: [{key: '0', value: {count: 45}},{key: '1', value: {count: 3}}, ... ]},
         {'2016': values: [{key: '0', value: {count: 67}},{key: '1', value: {count: 0}}, ... ]},
     {'2017': values: [{key: '0', value: {count: 12}},{key: '1', value: {count: 8}}, ... ]}
        ]

To better show how data looks like, here is the screen shot in case it helps clarification of the question.

Body:
Your data structure appears to be incorrect. You cannot have { '2015': values: [...] }. This would be the equivalent of { KEY: VALUE: VALUE}. The browser appears to be inferring meaning from your code and creating an object out of it anyway, but it's not right.

You can do an object of objects and have named inner objects, like this:

data = {
    2015: {
        values: [
            { key: "0", value: { count: 45 } },
            { key: "1", value: { count: 3 } },
        ],
    },
    2016: {
        values: [
            { key: "0", value: { count: 67 } },
            { key: "1", value: { count: 0 } },
        ],
    },
    2017: {
        values: [
            { key: "0", value: { count: 12 } },
            { key: "1", value: { count: 8 } },
        ],
    },
};

Or you can create an array of objects, like this:

data = [
    {
        year: 2015,
        values: [
            { key: "0", value: { count: 45 } },
            { key: "1", value: { count: 3 } },
        ],
    },
    {
        year: 2016,
        values: [
            { key: "0", value: { count: 67 } },
            { key: "1", value: { count: 0 } },
        ],
    },
    {
        year: 2017,
        values: [
            { key: "0", value: { count: 12 } },
            { key: "1", value: { count: 8 } },
        ],
    },
];

How you get the highest count property depends on which data structure you use.

Using the array of objects, I would approach the problem like this:

// create a temp storage array to store "count" property of each
const countArray = [];

// iterate through the outer objects
for (const outerObject of data) {

    // iterate through the objects that are in the "values" array
    for (const innerObject of outerObject.values) {

        // push the "count" value to the array
        countArray.push(innerObject.value.count)
    }
}

// sort the array in place, with highest values first
countArray.sort((a, b) => b - a);

// display the result
console.log(countArray[0])

You could do something similar for the object-of-objects data structure, but you'd need different syntax for that.


问:
Efficient looping and comparing properties of two similar objects
I have a function find() that needs to loop through a lot of objects to identify a similar object by comparing a bunch of properties.

```<code>class Target:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

class Source:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

def find(target: Target, source_set: set):
    for s in source_set:
        if s.a == target.a:
            if s.b == target.b:
                if s.c == target.c:
                    print("Found!")

source_set = {
    Source(a=1, b=2, c=3),
    Source(a=4, b=2, c=4)
}

target = Target(a=4, b=2, c=4)

find(target, source_set)
</code>```

The current function is very slow as my source_set can be millions.

The source_set creation and its Source objects can be adjusted (e.g. the type). The source_set itself is not modified after initialisation.

The Source objects creation's input is coming from a dict with the same properties. One Source's raw input data is like this:

```<code>{'a': '1', 'b': '2', 'c': '3'}
</code>```

The source_set is searched with many targets.

Is there a nice way to be more efficient? I'm hoping to not need to change the data structure.

答:
Using Pandas:

```<code># Python env: pip install pandas
# Miniconda env: conda install pandas
import pandas as pd

df = pd.DataFrame([s.__dict__ for s in source_set])
sr = pd.Series(target.__dict__)
print(df)
print(sr)

# Output of source_set
   a  b  c
0  4  2  4
1  1  2  3

# Output of target
a    4
b    2
c    4
dtype: int64
</code>```

Find same rows:

```<code>>>> sr.eq(df).all(axis=1).sum()
1
</code>```

Body:
I have a function find() that needs to loop through a lot of objects to identify a similar object by comparing a bunch of properties.

class Target:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

class Source:

    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

def find(target: Target, source_set: set):
    for s in source_set:
        if s.a == target.a:
            if s.b == target.b:
                if s.c == target.c:
                    print("Found!")

source_set = {
    Source(a=1, b=2, c=3),
    Source(a=4, b=2, c=4)
}

target = Target(a=4, b=2, c=4)

find(target, source_set)

The current function is very slow as my source_set can be millions.

The source_set creation and its Source objects can be adjusted (e.g. the type). The source_set itself is not modified after initialisation.

The Source objects creation's input is coming from a dict with the same properties. One Source's raw input data is like this:

{'a': '1', 'b': '2', 'c': '3'}

The source_set is searched with many targets.

Is there a nice way to be more efficient? I'm hoping to not need to change the data structure.

Body:
Using Pandas:

# Python env: pip install pandas
# Miniconda env: conda install pandas
import pandas as pd

df = pd.DataFrame([s.__dict__ for s in source_set])
sr = pd.Series(target.__dict__)
print(df)
print(sr)

# Output of source_set
   a  b  c
0  4  2  4
1  1  2  3

# Output of target
a    4
b    2
c    4
dtype: int64

Find same rows:

>>> sr.eq(df).all(axis=1).sum()
1


问:
Finding the difference in value counts by keys in two Dictionaries
I have two sample python dictionaries that counts how many times each key appears in a DataFrame.

```<code>dict1 =  {
           2000 : 2,
           3000 : 3,
           4000 : 4,
           5000 : 6,
           6000 : 8
          }

</code>```
```<code>dict2 = {
           4000 : 4,
           3000 : 3,
           2000 : 4,
           6000 : 10,
           5000 : 4
          }
</code>```

I would like to output the following where there is a difference.

```<code>diff = {
        2000 : 2
        5000 : 2
        6000 : 2
       }
</code>```

I would appreciate any help as I am not familiar with iterating though dictionaries. Even if the output shows me at which key there is a difference in values, it would work for me. I did the following but it does not produce any output.

```<code>for (k,v), (k2,v2) in zip(dict1.items(), dict2.items()):
    if k == k2:
        if v == v2:
            pass
        else:
            print('value is different at k')
</code>```

答:
Since you're counting... how about using Counters?

```<code>c1, c2 = Counter(dict2), Counter(dict1)
diff = dict((c1-c2) + (c2-c1))
</code>```

If you used Counters all around, you wouldn't need the conversions from dict and back. And maybe it would also simplify the creation of your two count dicts (Can't tell for sure since you didn't show how you created them).

Try it online!

Body:
I have two sample python dictionaries that counts how many times each key appears in a DataFrame.

dict1 =  {
           2000 : 2,
           3000 : 3,
           4000 : 4,
           5000 : 6,
           6000 : 8
          }

dict2 = {
           4000 : 4,
           3000 : 3,
           2000 : 4,
           6000 : 10,
           5000 : 4
          }

I would like to output the following where there is a difference.

diff = {
        2000 : 2
        5000 : 2
        6000 : 2
       }

I would appreciate any help as I am not familiar with iterating though dictionaries. Even if the output shows me at which key there is a difference in values, it would work for me. I did the following but it does not produce any output.

for (k,v), (k2,v2) in zip(dict1.items(), dict2.items()):
    if k == k2:
        if v == v2:
            pass
        else:
            print('value is different at k')

Body:
Since you're counting... how about using Counters?

c1, c2 = Counter(dict2), Counter(dict1)
diff = dict((c1-c2) + (c2-c1))

If you used Counters all around, you wouldn't need the conversions from dict and back. And maybe it would also simplify the creation of your two count dicts (Can't tell for sure since you didn't show how you created them).

Try it online!


问:
Sending parameter to Link to a Router component Reacts
Im currently trying to send a state from the Link component to the Router component.

The router component looks like this:

```<code><Route
  exact
  path='/banner/edit/:id'
>
  {!user && <Redirect to="/login" />}
  {user && org && <EditBanner uid={user.uid} org={org} />}
</Route>
</code>```

This component is only rendered when the user is not null, and when the org is not null.

The EditBanner has a state called: bannerTitle:

```<code>export const EditBanner = ({ uid, org }) => {

  // States
  const [bannerTitle, setBannerTitle] = useState(null);
  ...
</code>```

And when I am using Link to go to the component, I want to pass in the bannerTitle as a property to set the state in the EditBanner component. However, this is not having any effect on the Component.

```<code><Link
  to={{
    pathname: "/banner/edit/" + banner.id,
    state: { bannerTitle: "HELLO" }
  }}
>
  Edit
</Link>
</code>```

Where can I get the passed props?

答:
You can use the useLocation hook which provides a location object which has state:

```<code>import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import {useLocation} from "react-router-dom";

export const EditBanner = ({ uid, org }) => {
  let location = useLocation();
  useEffect(() => {
    console.log(location.state);
  }, [location])

  // ...
}
</code>```

Hopefully that helps!

Body:
Im currently trying to send a state from the Link component to the Router component.

The router component looks like this:

<Route
  exact
  path='/banner/edit/:id'
>
  {!user && <Redirect to="/login" />}
  {user && org && <EditBanner uid={user.uid} org={org} />}
</Route>

This component is only rendered when the user is not null, and when the org is not null.

The EditBanner has a state called: bannerTitle:

export const EditBanner = ({ uid, org }) => {

  // States
  const [bannerTitle, setBannerTitle] = useState(null);
  ...

And when I am using Link to go to the component, I want to pass in the bannerTitle as a property to set the state in the EditBanner component. However, this is not having any effect on the Component.

<Link
  to={{
    pathname: "/banner/edit/" + banner.id,
    state: { bannerTitle: "HELLO" }
  }}
>
  Edit
</Link>

Where can I get the passed props?

Body:
You can use the useLocation hook which provides a location object which has state:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import {useLocation} from "react-router-dom";

export const EditBanner = ({ uid, org }) => {
  let location = useLocation();
  useEffect(() => {
    console.log(location.state);
  }, [location])

  // ...
}

Hopefully that helps!


问:
vscode "no refactorings available" for python
Ctrl + alt + R for extension python.python 2020.1.58038 always gives me a "No refactorings available" message.

Probably a configuration issue but I've tried several times to uninstall/reinstall and restart vs code to no avail.

Thought maybe I was missing python-rope but python -m pip install --upgrade rope
Requirement already up-to-date: rope in c:\users\cdoyle\appdata\roaming\python\python37\site-packages (0.16.0)

VS Code Version info :
Version: 1.42.0 (user setup)
Commit: ae08d5460b5a45169385ff3fd44208f431992451
Date: 2020-02-06T10:51:34.058Z
Electron: 6.1.6
Chrome: 76.0.3809.146
Node.js: 12.4.0
V8: 7.6.303.31-electron.0
OS: Windows_NT x64 10.0.18362

Also I don't see any open issues
https://github.com/Microsoft/vscode-python/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+refactoring

Not sure what to try next.

Thanks

答:
Visual Studio Code and its Python extension is (at the time of writing this) very limited when it comes to refactoring. Out of the box it provides two refactoring actions: Extract Method and Extract Variable. The reason you're seeing "No refactorings available" is because the currently selected text doesn't match any of these actions. Try selecting a line of text and then press [Ctrl][Shift][R].

Rope support was removed in VSCode in favour of Language Server Protocol integration which is used by their Pylance language server extension. Pylance is now installed automatically with vscode-python extension, and it's actively developed - maybe they will implement more refactorings in the future. If you're looking for more robust refactoring, check out PyCharm refactoring, it is currently much more sophisticated.